/*
 * I am converting this grammar to Python. - nfd 11/Jul/2005
*/

/*
 * PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
 *
 * Authors: Sumana Srinivasan, NeXT Inc.;            sumana_srinivasan@next.com
 *          Terence Parr, Parr Research Corporation; parrt@parr-research.com
 *          Russell Quong, Purdue University;        quong@ecn.purdue.edu
 *
 * VERSION 1.2
 *
 * SOFTWARE RIGHTS
 *
 * This file is a part of the ANTLR-based C++ grammar and is free
 * software.  We do not reserve any LEGAL rights to its use or
 * distribution, but you may NOT claim ownership or authorship of this
 * grammar or support code.  An individual or company may otherwise do
 * whatever they wish with the grammar distributed herewith including the
 * incorporation of the grammar or the output generated by ANTLR into
 * commerical software.  You may redistribute in source or binary form
 * without payment of royalties to us as long as this header remains
 * in all source distributions.
 *
 * We encourage users to develop parsers/tools using this grammar.
 * In return, we ask that credit is given to us for developing this
 * grammar.  By "credit", we mean that if you incorporate our grammar or
 * the generated code into one of your programs (commercial product,
 * research project, or otherwise) that you acknowledge this fact in the
 * documentation, research report, etc....  In addition, you should say nice
 * things about us at every opportunity.
 *
 * As long as these guidelines are kept, we expect to continue enhancing
 * this grammar.  Feel free to send us enhancements, fixes, bug reports,
 * suggestions, or general words of encouragement at parrt@parr-research.com.
 * 
 * NeXT Computer Inc.
 * 900 Chesapeake Dr.
 * Redwood City, CA 94555
 * 12/02/1994
 * 
 * Restructured for public consumption by Terence Parr late February, 1995.
 *
 * DISCLAIMER: we make no guarantees that this grammar works, makes sense,
 *             or can be used to do anything useful.
 */
/* 2001-2002
 * Version 1.0
 * This C++ grammar file has been converted from PCCTS to run under 
 *  ANTLR to generate lexer and parser in C++ code by
 *  Jianguo Zuo and David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 */
/* 2003
 * Version 2.0 was published by David Wigg in September 2003
 */
/* 2004
 * Version 3.0 July 2004
 * This is version 3.0 of the C++ grammar definition for ANTLR to 
 *  generate lexer and parser in C++ code updated by
 *  David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 * wiggjd@bcs.ac.uk
 * blackse@lsbu.ac.uk
 *
 * See MyReadMe.txt for further information
 *
 * This file is best viewed in courier font with tabs set to 4 spaces
 */

header 
    {
    // The statements in this block appear in both CPPLexer.py and CPPParser.py
    from CPPDictionary import CPPDictionary
    from LineObject import LineObject
    import CPPSymbol
    from var_types import * # "Do not use. Should be deleted in the next version"
    from enum_types import *
    // Auto-conversion hack - nfd
    false = False
    true = True
    NULL = None
	def printf(fmt, *args): print fmt % (args)
    }

header "CPPLexer.__init__"
{
self.line_directive_handler = kwargs.get("line_directive_handler")
self.lineObject = LineObject()
self.originalSource = ""

self._line = 0
}

header "CPPParser.__init__"
{//antlrTrace(False);    // This is a dynamic trace facility for use with -traceParser etc.
/* It requires modification in LLkParser.cpp and LLkParser.hpp
otherwise it should be commented out (see MyReadMe.txt)
true shows antlr trace (can be set and reset during parsing)
false stops showing antlr trace 
Provided the parser is always generated with -traceParser this
facility allows trace output to be turned on or off by changing
the setting here from false to true or vice versa and then
recompiling and linking CPPParser only thus avoiding the need
to use antlr.Tool to re-generate the lexer and parser again. 
*/

// Creates a dictionary to hold symbols with 4001 buckets, 200 scopes and 800,000 characters
// These can be changed to suit the size of program(s) being parsed
// nfd: The Python version uses Python's native dict, which has "infinite" capacity, so
// the above params aren't passed in.
self.symbols = CPPDictionary()

// Set template parameter and external scopes
// Set template parameter scope to 0
self.templateParameterScope = self.symbols.getCurrentScopeIndex()
self.symbols.saveScope()    // Advance currentScope from 0 to 1
self.externalScope = self.symbols.getCurrentScopeIndex()    // Set external scope to 1

// Declare predefined scope "std" in external scope
a = CPPSymbol.CPPSymbol("std", CPPSymbol.otTypedef)
self.symbols.define("std", a)

// Global flags to allow for nested declarations
self._td = False        // For typedef
self._fd = False        // For friend
self._ts = None         // For TypeSpecifier
self._ds = dsInvalid    // For DeclSpecifier

// 0 = Function definition not being parsed
// 1 = Parsing function name
// 2 = Parsing function parameter list
// 3 = Parsing function block
self.functionDefinition = 0
self.qualifierPrefix = "" // [0] = '\0';
self.enclosingClass = "";
self.assign_stmt_RHS_found = 0;
self.in_parameter_list = False;
self.K_and_R = False;    // used to distinguish old K & R parameter definitions
self.in_return = False;
self.is_address = False;
self.is_pointer = False;

// "protected:"
}

options
	{
	language = "Python";
	}

{

//	The statements in this block appear only in CPPParser.py and not in CPPLexer.py

// Used to control selected (level) tracing (see support.cpp)
// 1 Shows which external and member statements selected
// 2 Shows above plus all declarations/definitions
// 3 reserved for future use
// 4 and above available for user
statementTrace = 0

def trace1(s):
    if statementTrace >= 1:
        print s

def checknode(node):
    assert node is not None
    return node

CPPParser_MaxQualifiedItemSize = 500


// Limit lookahead for qualifiedItemIs()
MaxTemplateTokenScan = 200 

}	// End of CPPParser.cpp block


class CPPParser extends Parser;

options
	{
	k = 2;
	exportVocab = STDC;
	buildAST = false;
	codeGenMakeSwitchThreshold = 2;
	codeGenBitsetTestThreshold = 3;
	}


translation_unit returns [node]
   
   :  {self.enterExternalScope();} {node = self.node("translation_unit");}
      (ed = external_declaration {node.add_child(ed);})+
	  EOF
      {self.exitExternalScope();}
   ;

external_declaration returns [node]
	{self.K_and_R = false;}
	:  
	(
	// Template explicit specialisation (DW 14/04/03)
	// Ref: http://msdn2.microsoft.com/library/c401y1kb(en-us,vs.80).aspx (nfd)
		("template" LESSTHAN GREATERTHAN)=>
		"template" LESSTHAN GREATERTHAN d = declaration
		{node = self.node("template_specialisation"); node.add_child(d);}
	|
	// Class definition (templates too)
	// This is separated out otherwise the next alternative
	// would look for "class A {...} f() {...}" which is
	// an unacceptable level of backtracking.

	// JEL Note:  Rule body does not need typedef, because
	// that is internal to "declaration", and it is invalid
	// to say "typedef template..."
	 	// Class definition
		(("typedef")? class_head)=>
		d = declaration {node = d;}
	|	
		// Class template definition
		(template_head class_head)=>
		th = template_head d = declaration
		{node = self.node("template"); node.add_child(th); node.add_child(d);}
   |  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{node = self.node("enum");}
		es = enum_specifier {node.add_child(es);}
		(idl = init_declarator_list {node.add_child(idl);})?
		SEMICOLON! {self.end_of_stmt();}
   |  
		// Destructor DEFINITION (templated or non-templated)
		((template_head)? dtor_head[1] LCURLY)=>
		(th = template_head)? dh = dtor_head[1] db = dtor_body
		{node = self.node("unfinished_destructor");}
	|  
		// Constructor DEFINITION (non-templated)
		// JEL 4/3/96 Added predicate that works, once the
		// restriction is added that ctor cannot be virtual
		// and ctor_declarator uses a more restrictive id
		(	(options {warnWhenFollowAmbig = false;}:
			 cds = ctor_decl_spec)?
			{self.qualifiedItemIsOneOf(qiCtor)}?
		)=>
		cd = ctor_definition
		{node = self.node("unfinished_non-templated constructor");}
   |  
		// User-defined type cast
		(("inline")? scope_override  conversion_function_decl_or_def)=>
		("inline")? s = scope_override cfdd = conversion_function_decl_or_def 
		{node = self.node("unfinished_typecast");}
   |   
		// Function declaration
		(declaration_specifiers function_declarator[0] SEMICOLON!)=> 
		d = declaration
		{node = d;}
	|
		// Function definition
		(declaration_specifiers	function_declarator[1] LCURLY)=> 
		fd = function_definition {node = fd;}
	|
		// K & R Function definition
		(declaration_specifiers	function_declarator[1] declaration)=>
		{self.K_and_R = true;}
		fd = function_definition {node = fd;}
	|  
		// templated forward class decl, init/decl of static member in template
		(template_head declaration_specifiers (init_declarator_list)? SEMICOLON! {self.end_of_stmt();})=>
		{beginTemplateDeclaration();}
		th = template_head ds = declaration_specifiers (idl = init_declarator_list)? SEMICOLON! {self.end_of_stmt();}
		{endTemplateDeclaration();}
		{node = self.node("unfinished_templated_forward_class_decl");}
	|  
		// Templated FUNCTIONS and CONSTRUCTORS matched here.
		{beginTemplateDefinition();}
		th = template_head
		{node = self.node("templated_function");}
		(  
			// Templated CONSTRUCTOR definition
            // JEL 4/3/96 Added predicate that works once the
            // restriction is added that ctor cannot be virtual
			(	ctor_decl_spec {self.qualifiedItemIsOneOf(qiCtor)}?)=>
			cd = ctor_definition {node.add_child(cd);}
		|
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON!)=> 
			d = declaration
			{node.add_child(d);}
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			fd = function_definition {node.add_child(fd);}
		)
		{endTemplateDefinition();}
	|  
		dn = decl_namespace
		{node = self.node("unfinished_namespace_decl");}
	|	
		// everything else (except templates)
		d = declaration {node = d;}
	|	
		SEMICOLON! {self.end_of_stmt();}
	)
	;	// end of external_declaration

decl_namespace returns [node]
	
	:	
		"namespace" 
		(
			{node = self.node("namespace");}
			(ns:ID {node.set_leaf(ns.getText());}
			{self._td = true; self.declaratorID(ns.getText(), qiType);})?
			// The following statement can be invoked to trigger selective antlr trace
			// Also see below
			//{if (strcmp(ns.getText():,"xyz")==0) antlrTrace(True);}	// Used for diagnostic trigger
			LCURLY 
			{self.enterNewLocalScope();}
			(ed = external_declaration {node.add_child(ed);} )*
			{self.exitLocalScope();}
			RCURLY
			// The following should be implemented to match the optional statement above
			//{antlrTrace(False);}
		|
			{node = self.node("unfinished_namespace_assignment");}
			ns2:ID 
			{self._td = true; self.declaratorID(ns2.getText(), qiType);}
			ASSIGNEQUAL qid = qualified_id SEMICOLON! {self.end_of_stmt();} 
		)
	;

member_declaration returns [node]
	
	:
	(
		// Class definition
		// This is separated out otherwise the next alternative
		// would look for "class A {...} f() {...}" which is
		// an unacceptable level of backtracking.
		( ("typedef")? class_head) => 
		d = declaration
		{node = d;}
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{node = self.node("member_declaration");}
		es = enum_specifier {node.add_child(es);}
		(mdl = member_declarator_list {node.add_child(mdl);})? SEMICOLON!	{self.end_of_stmt();}
	|
		// Constructor declarator
		(	ctor_decl_spec
			{self.qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[0] SEMICOLON!
		)=>
		{node = self.node("member_declaration");}
		cds = ctor_decl_spec  {node.add_child(cds);}
		cd = ctor_declarator[0] {node.add_child(cd);}
		SEMICOLON! {self.end_of_stmt();} // Constructor declarator
	|  
		// JEL Predicate to distinguish ctor from function
		// This works now that ctor cannot have VIRTUAL
		// It unfortunately matches A::A where A is not enclosing
		// class -- this will have to be checked semantically
		(	ctor_decl_spec
			{self.qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[1]
			(COLON        // DEFINITION :ctor_initializer
			|LCURLY       // DEFINITION (compound Statement) ?
			)
		)=>
		{node = self.node("member_declaration");}
		cd = ctor_definition  {node.add_child(cd);}
   |  
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		(dtor_head[0] SEMICOLON!)=>
		{node = self.node("member_declaration");}
		dh = dtor_head[0] {node.add_child(dh);}
		SEMICOLON! {self.end_of_stmt();}	// Declaration
	|
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		(dtor_head[1] LCURLY)=>
		{node = self.node("member_declaration");}
		dh = dtor_head[1] {node.add_child(dh);}
		db = dtor_body	{node.add_child(db);}// Definition
	|
		// Function declaration
		(declaration_specifiers	function_declarator[0] SEMICOLON!)=>
		d = declaration
		{node = d;}
	|  
		// Function definition
		(declaration_specifiers function_declarator[1] LCURLY)=>
		{self.beginFieldDeclaration();}
		fd = function_definition
		{node = fd;}
	|  
		// User-defined type cast
		(("inline")? conversion_function_decl_or_def)=>
		("inline")? cfdd = conversion_function_decl_or_def
		{node = self.node("unfinished_udtc-439");}
	|  
		// Hack to handle decls like "superclass::member",
		// to redefine access to private base class public members
		(qualified_id SEMICOLON!)=>
		q = qualified_id SEMICOLON! {self.end_of_stmt();}
		{node = self.node("unfinished_declhack-446");}
	|  
		// Member with a type or just a type def
		// A::T a(), ::T a, ::B a, void a, E a (where E is the enclosing class)
		(declaration_specifiers)=>
		{self.beginFieldDeclaration();}
		{node = self.node("member_declaration");}
		ds = declaration_specifiers {node.add_child(ds);}
		(md = member_declarator_list {node.add_child(md);})?
		SEMICOLON! {self.end_of_stmt();}
	|  
		// Member without a type (I guess it can only be a function declaration or definition)
		(function_declarator[0] SEMICOLON!)=>
		{self.beginFieldDeclaration();}
		fd = function_declarator[0] SEMICOLON! {self.end_of_stmt();}
		{node = fd;}
	|
		// Member without a type (I guess it can only be a function definition)
		fd = function_declarator[1] cs = compound_statement {self.endFunctionDefinition();}
		{node = self.node("member_declaration"); node.add_child(fd); node.add_child(cs);}
	|  
		// templated forward class decl, init/decl of static member in template
		// DW 27/06/03 Copied here from external_declaration since templates can now be nested
		(template_head ds = declaration_specifiers (init_declarator_list)? SEMICOLON!)=>
		{beginTemplateDeclaration(); node = self.node("member_declaration");}
		 th = template_head {node.add_child(th);}
		 ds = declaration_specifiers {node.add_child(ds);}
		 (idl = init_declarator_list {node.add_child(idl);} )? SEMICOLON!
		 {self.end_of_stmt();}
		{endTemplateDeclaration();}
	|  
		// Templated FUNCTIONS and CONSTRUCTORS matched here.
		// DW 27/06/03 Copied here from external_declaration since templates can now be nested
		{beginTemplateDefinition();}
		th = template_head {node = self.node("templated_function"); node.add_child(th);}
		(
			// Templated CONSTRUCTOR definition
			// JEL 4/3/96 Added predicate that works once the
			// restriction is added that ctor cannot be virtual
			(ctor_decl_spec
			 {self.qualifiedItemIsOneOf(qiCtor)}?
			)=>
			cd = ctor_definition {node.add_child(cd);}
		|
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON!)=>
			d = declaration {node.add_child(d);}
		|  
			// Templated function definition
			// Function definition DW 2/6/97
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			fd = function_definition {node.add_child(fd);}
		|
			cfdd = conversion_function_decl_or_def {node.add_child(cfdd);}
		)
		{endTemplateDefinition();}
	|  
		as = access_specifier COLON
		{node = as;}
	|  
		SEMICOLON! {self.end_of_stmt();}
		{node = self.node("unfinished_member-decl-524");}
	)
	;	// end member_declaration

function_definition returns [node]
	
	:	// don't want next action as an init-action due to (...)=> caller
	{self.beginFunctionDefinition(); node = self.node("function_definition");}
	(	// Next line is equivalent to guarded predicate in PCCTS
		// (SCOPE | ID)? => <<self.qualifiedItemIsOneOf(qiType|qiCtor)>>?
		{( not(self.LA(1)==SCOPE or self.LA(1)==ID) or self.qualifiedItemIsOneOf(qiType|qiCtor) )}?
		ds = declaration_specifiers {node.add_child(ds);}
		fd = function_declarator[1] {node.add_child(fd);}
		(	options{warnWhenFollowAmbig = false;}:
			{decl_node = self.node("declaration_list");}
			(d = declaration {decl_node.add_child(d);})*	// Possible for K & R definition
			{self.in_parameter_list = false;}
			{node.add_child(decl_node);}
		)?
		cs = compound_statement {node.add_child(cs);}
	|	// Next line is equivalent to guarded predicate in PCCTS
		// (SCOPE | ID)? => <<self.qualifiedItemIsOneOf(qiPtrMember)>>?
		//{( !(self.LA(1)==SCOPE||self.LA(1)==ID) || (self.self.qualifiedItemIsOneOf(qiPtrMember)) )}?
		fd = function_declarator[1] {node.add_child(fd);}
		(	options{warnWhenFollowAmbig = false;}:
			{decl_node = self.node("declaration_list");}
			(d = declaration)*	 {decl_node.add_child(d);}// Possible for K & R definition
			{self.in_parameter_list = false;}
			{node.add_child(decl_node);}
		)?
		cs = compound_statement {node.add_child(cs);}
	)
	{self.endFunctionDefinition();}
	;

declaration returns [node]
	
	:	
		("extern" StringLiteral)=>
		ls = linkage_specification {node = ls;}
	|	
		{self.beginDeclaration(); node = self.node("declaration");}
		// LL 31/1/97: added (COMMA) ? below. This allows variables to typedef'ed more than once. DW 18/08/03 ?
		ds = declaration_specifiers {node.add_child(ds);}
		((COMMA)?
			(a = attribute {node.add_child(a);})?
			idl = init_declarator_list {node.add_child(idl);} )?
		SEMICOLON! {self.end_of_stmt();}
		{self.endDeclaration();}
	|	
		ud = using_declaration	// DW 19/04/04
		{node = ud;}
	;

linkage_specification returns [node]
	{node = self.node("linkage_specification");}
	:	"extern"
		StringLiteral
		(LCURLY (ed = external_declaration {node.add_child(ed);})* RCURLY
		|d = declaration {node.add_child(d);}
		)
	;

declaration_specifiers returns [node]
	{// Global flags to allow for nested declarations
	self._td = false;		// For typedef
	self._fd = false;		// For friend
	self._tq = None;	// For TypeQualifier
	self._ts = None;	// For TypeSpecifier
	self._ds = None;	// For DeclSpecifier

	 // Locals
	td = false;	// For typedef
	fd = false;	// For friend
	sc = "";	// auto,register,static,extern,mutable
	tq = "";	// const,const_cast,volatile,cdecl
	ts =  NULL;	// char,int,double, etc., class,struct,union
	// inline,virtual,explicit:
	ds = None}
	:
	(	
		{node = self.node("declaration_specifiers");}
		(options {warnWhenFollowAmbig = false;}
		:
		(sc = storage_class_specifier {specname = sc;}
		|	tq = type_qualifier {specname = tq;}
		|   "__extension__" {specname = "__extension__";} /* nfd: gcc extension */
		|	("inline"^|"_inline"^|"__inline"^|"__inline__")
				{ds = dsINLINE; specname = "inline";}
		|	"virtual"^						{ds = dsVIRTUAL; specname = "virtual";}
		|	"explicit"^						{ds = dsEXPLICIT; specname = "explicit";}
		|	"typedef"^	{td=true;} {specname = "typedef";}
		|	"friend"^	{fd=true;} {specname = "friend";}
		|	("_stdcall"^|"__stdcall"^) {specname = "stdcall";}
		)
		{node.add_child(self.node(specname));}

		)*
		ts = type_specifier[ds] {node.add_child(ts);}
	|	
		"typename"	{td=true;}
		{node = self.node("declaration_specifiers");}
		dd = direct_declarator  {node.add_child(dd); node.set_leaf("typename");}
	)
	{self.declarationSpecifier(td,fd,sc,tq,ts,ds);}
	;

attribute returns [a]  /* nfd */
	{a = self.node("attribute");}
	: "__attribute__" LPAREN LPAREN adl = attribute_decl_list {a.add_child(adl);} RPAREN RPAREN
	;

attribute_decl_list returns [node]
	{node = self.node("attribute_decl_list");}
	: "__mode__" LPAREN ID RPAREN {node.set_name("mode");}
	| "packed" {node.set_name("packed");}
	| "const" {node.set_name("const");}
	| "__const" {node.set_name("const");} /* nfd: gcc extension */
	| "__noreturn__" {node.set_name("noreturn");}
	| "__returns_twice__" {node.set_name("returns_twice");}
	| "__noinline__" {node.set_name("noinline");}
	| "__always_inline__" {node.set_name("always_inline");}
	| "__flatten__" {node.set_name("flatten");}
	| "__pure__" {node.set_name("pure");}
	| "__const__" {node.set_name("const");}
	| "__nothrow__" {node.set_name("nothrow");}
	| "__sentinel__" {node.set_name("sentinel");}
	| "__format__" {node.set_name("format");} LPAREN ID COMMA c1=constant {node.add_child(c1);}
			COMMA c2=constant {node.add_child(c2);} RPAREN
	| "__format_arg__" {node.set_name("format_arg");}
	| "__no_instrument_function__" {node.set_name("no_instrument_function");}
	| "__section__" {node.set_name("section");}
	| "__constructor__" {node.set_name("constructor");}
	| "__destructor__" {node.set_name("destructor");}
	| "__used__" {node.set_name("used");}
	| "__unused__" {node.set_name("unused");}
	| "__deprecated__" {node.set_name("deprecated");}
	| "__weak__" {node.set_name("weak");}
	| "__malloc__" {node.set_name("malloc");}
	| "__alias__" {node.set_name("alias");}
	| "__warn_unused_result__" {node.set_name("warn_unused_result");}
	| "__nonnull__" {node.set_name("nonnull");} LPAREN c1=constant {node.add_child(c1);}
			(COMMA c2=constant {node.add_child(c2);})* RPAREN
	| "__externally_visible__" {node.set_name("externally_visible");}
	;

storage_class_specifier returns [s]
	:	"auto"		{s = "auto";}
	|	"register"	{s = "register";}
	|	"static"	{s = "static";}
	|	"extern"	{s = "extern";}
	|	"mutable"	{s = "mutable";}
	;

type_qualifier returns [s] // aka cv_qualifier
	:  ("const"|"const_cast"|"__const")	{s = "const";} 
	|  ("volatile"|"__volatile")				{s = "volatile";}
	|  ("__restrict" | "__restrict__") {s = "__restrict";}
	;

type_specifier[ ds] returns [node]
	:	node = simple_type_specifier
	|	node = class_specifier[ds]
	|	node = enum_specifier
	;

simple_type_specifier returns [node]
	{node = self.node("simple_type_specifier");}
	:	(	{self.qualifiedItemIsOneOf(qiType|qiCtor)}? 
			 s = qualified_type {node.add_child(self.node(s));}
		|	
			(	"char"		{node.add_child(self.node("char"));}
			//|	"wchar_t"	{ts |= tsWCHAR_T;}  
			|	"bool"		{node.add_child(self.node("bool"));}
			|	"short"		{node.add_child(self.node("short"));}
			|	"int"		{node.add_child(self.node("int"));}
			|	("_int64"|"__int64")	{node.add_child(self.node("__int64"));}
			|	"__w64"		{node.add_child(self.node("__w64"));}
			|	"long"		{node.add_child(self.node("long"));}
			/* nfd: GCC type aliases for "signed" */
			|	("signed"^|"__signed"^|"__signed__"^)	{node.add_child(self.node("signed"));}
			|	"unsigned"	{node.add_child(self.node("unsigned"));}
			|	"float"		{node.add_child(self.node("float"));}
			|	"double"	{node.add_child(self.node("double"));}
			|	"void"		{node.add_child(self.node("void"));}
			|	("_declspec"|"__declspec") LPAREN ID RPAREN 
			|   "__builtin_va_list" {node.add_child(self.node("__builtin_va_list"));}
			)+
		|
		// Fix towards allowing us to parse *.cpp files directly
		(qualified_type qualified_id)=> s = qualified_type {node.add_child(self.node(s));}
		)
	;

qualified_type returns [q]
	
	: 
		// JEL 3/29/96 removed this predicate and moved it upwards to
		// simple_type_specifier.  This was done to allow parsing of ~ID to 
		// be a unary_expression, which was never reached with this 
		// predicate on
		// {self.qualifiedItemIsOneOf(qiType|qiCtor)}?

		s = scope_override 
		id:ID 
		(options {warnWhenFollowAmbig = false;}:
		 LESSTHAN tal = template_argument_list GREATERTHAN
		)?
		{qitem = s;}
		{qitem +=  id.getText();}
		{q = qitem;}
	;

class_specifier[ ds] returns [node]
	
	:	("class"^	{ts = "struct"; node = self.node("class");}	
		|"struct"^	{ts = "union"; node = self.node("struct");}
		|"union"^	{ts = "class"; node = self.node("union");}
		)
		(	id = qualified_id {node.set_leaf(id);}
			(options{generateAmbigWarnings = false;}:
				{saveClass = self.enclosingClass; self.enclosingClass = id;}
				(bases = base_clause {node.add_child(bases);})?
				LCURLY	 
				{self.beginClassDefinition(ts, id);}	// This stores class name in dictionary
				{members = self.node("members");}
				(md = member_declaration {members.add_child(md);})*
				{self.endClassDefinition();}
				RCURLY
				{node.add_child(members); self.enclosingClass = saveClass;}
			|
				{self.classForwardDeclaration(ts, ds, id);}
			)
		|
			LCURLY	 
			{saveClass = self.enclosingClass; self.enclosingClass = "__anonymous";}
			{self.beginClassDefinition(ts, "anonymous");}
			{members = self.node("members");}
			(md = member_declaration {members.add_child(md);})*
			{self.endClassDefinition();}
			{node.add_child(members);}
			RCURLY
			{self.enclosingClass = saveClass;}
		) 
		(a = attribute {node.add_child(a);})?
	;

enum_specifier returns [node]
	{node = self.node("enum_specifier");}
	:	"enum"
		(	LCURLY el = enumerator_list {node.add_child(el);}RCURLY
		|	id:ID     {node.set_leaf(id.getText());}
				// DW 22/04/03 Suggest qualified_id here to satisfy elaborated_type_specifier
			{self.beginEnumDefinition(id.getText());}
			(LCURLY el = enumerator_list {node.add_child(el);} RCURLY)?
			{self.endEnumDefinition();}
		)
	;

/* nfd: Optional trailing comma is a GCC-ism (mar 14 2006)*/
enumerator_list returns [node]
	{node = self.node("enumerator_list");}
	:	e = enumerator {node.add_child(e);}
		/* nfd : it's always okay to choose this option when available,
		 * rather than the trailing comma and an error.
		*/
		( options {warnWhenFollowAmbig=false;} : COMMA e = enumerator {node.add_child(e);})*
		(COMMA)?
	;

enumerator returns [node]
	{node = self.node("enumerator");}
	:	id:ID {node.set_leaf(id.getText());}
		(ASSIGNEQUAL cx = constant_expression {node.add_child(cx);})?
		{self.enumElement(id.getText());}
	;

/* This matches a generic qualified identifier ::T::B::foo
 * (including OPERATOR).
 * It might be a good idea to put T::~dtor in here
 * as well, but id_expression in expr.g puts it in manually.
 * Maybe not, 'cause many people use this assuming only A::B.
 * How about a 'qualified_complex_id'?
 */
qualified_id returns [q]
	
	:
	so =  scope_override
	{qitem = so;}
	(  
	id:ID	(options{warnWhenFollowAmbig = false;}:
			 LESSTHAN tal = template_argument_list GREATERTHAN)?
	{qitem += id.getText();}
	|  
	OPERATOR o = optor
	{qitem += "operator"; qitem +=  o;}
	|
	"this"  // DW 21/07/03 fix to pass test8.i
	|
	("true"|"false")	// DW 21/07/03 fix to pass test8.i
	)
	{q = qitem;}
	;

typeID
	:	{self.isTypeName(self.LT(1).getText())}?
		ID
	;

init_declarator_list returns [node]
	{node = self.node("init_declarator_list");}
	:	id = init_declarator {node.add_child(id);}
		(COMMA id = init_declarator {node.add_child(id);})*
		(a = attribute {node.add_child(a);})*
	;

init_declarator returns [node]
	{node = self.node("init_declarator");}
	:	d = declarator {node.add_child(d);}
		(an = func_asm_name {node.add_child(an);})?
		(	
			ASSIGNEQUAL 
			i = initializer
			{node.add_child(i);}
		|	
			LPAREN el = expression_list RPAREN
			{node.add_child(el);}
		)?
	;

initializer returns [node]
   {node = self.node("initializer");}
   :  rx = remainder_expression {node.add_child(rx);}// DW 18/4/01 assignment_expression
   |  LCURLY i1 = initializer {node.add_child(i1);}
   		(COMMA i2 = initializer {node.add_child(i2);})* RCURLY
   |  d1 = gcc_designator {node.add_child(d1);}
   	i3 = initializer {node.add_child(i3);} /* nfd jul 2005 */
   |  d2 = c99_designator {node.add_child(d2);}
   		i4 = initializer {node.add_child(i4);}/* nfd jul 2005 */
   ;
 
/* Designated initializers, GCC extension, http://tigcc.ticalc.org/doc/gnuexts.html#SEC82 
 * These are of the form var = {structfield : val}
 * See below for c99 designators.
*/
gcc_designator returns [node]
	{node = self.node("designator");}
	: id:ID COLON {node.set_leaf(id.getText());}
	;

/* C99 designated initializers, http://david.tribble.com/text/cdiffs.htm#C90-vs-CPP98
 * Of the form var = {.structfield = val}
*/
c99_designator returns [node]
	{node = self.node("designator");}
	: DOT id:ID EQUALS {node.set_leaf(id.getText());}
	;

class_head returns [node]
	{node = self.node("class_head") ;}
	:	// Used only by predicates	
	("struct" {node.add_child(self.node("struct"));}
	|"union" {node.add_child(self.node("union"));}
	|"class" {node.add_child(self.node("class"));}
	)
    (id:ID	{node.set_leaf(id.getText());}
		(LESSTHAN tal= template_argument_list {node.add_child(tal);} GREATERTHAN)?
		(bc = base_clause {node.add_child(bc);})? 
	)? LCURLY
	;

base_clause returns [node]
	{node = self.node("base_clause");}
	:	COLON bs = base_specifier {node.add_child(bs);}
		(COMMA bs = base_specifier {node.add_child(bs);})*
	;

base_specifier returns [node]
	
	:	// DW 13/08/03 Should check qualified_type for class-name?
	{node = self.node("base_specifier");}
	(	"virtual" {node.add_child(self.node("virtual"));}
		(as = access_specifier {node.add_child(as);})?
		qt = qualified_type {node.add_child(self.node(qt));}
	|	as = access_specifier {node.add_child(as);}
		("virtual" {node.add_child(self.node("virtual"));})?
		qt = qualified_type {node.add_child(self.node(qt));}
	|	qt = qualified_type {node.add_child(self.node(qt));}
	)
	;

access_specifier returns [node]
	:	"public" {node = self.node("public");}
	|	"protected" {node = self.node("protected");}
	|	"private" {node = self.node("private");}
	;

member_declarator_list returns [node]
	{node = self.node("init_declarator_list");}
	:	md = member_declarator {node.add_child(md);}
		(COMMA md = member_declarator {node.add_child(md);} )*
	;

member_declarator returns [node]
	
	:	
		{node = self.node("init_declarator_bitfield");}
		((ID)? COLON constant_expression)=>(id:ID {node.set_leaf(id.getText());})?
		COLON c = constant_expression {node.add_child(c);}
		(ASSIGNEQUAL OCTALINT {node.add_child(self.node("purevirtual"));})?
	|  
		d = declarator {node = self.node("init_declarator"); node.add_child(d);}
		(a = attribute {node.add_child(a);})?
		(ASSIGNEQUAL OCTALINT {node.add_child(self.node("purevirtual"));})?
	;

conversion_function_decl_or_def returns [node]
		{node = self.node("unfinished_conversion_function_decl_or_def");}
	:	OPERATOR ds = declaration_specifiers (STAR | AMPERSAND)?	// DW 01/08/03 Use type_specifier here? see syntax
		(LESSTHAN tpl = template_parameter_list GREATERTHAN)?
		LPAREN (pl = parameter_list)? RPAREN	
		(tq = type_qualifier)?
		(es = exception_specification)?
		(	cs = compound_statement
		|	SEMICOLON! {self.end_of_stmt();}
		)
	;

// JEL note:  does not use (const|volatile)* to avoid lookahead problems
cv_qualifier_seq returns [s]
	{seq = ""}
	:
	(tq = type_qualifier {seq +=  tq;})*
	{s = seq;}
	;

declarator returns [node]
	
	:
		{node = self.node("declarator");}
		//{( !(self.LA(1)==SCOPE||self.LA(1)==ID) || self.qualifiedItemIsOneOf(qiPtrMember) );}?
		(ptr_operator)=> p = ptr_operator {node.set_leaf(p);}	// AMPERSAND or STAR
		d = declarator {node.add_child(d);}
	|	
		{node = self.node("declarator");}
		d = direct_declarator {node.add_child(d);}
	;

direct_declarator returns [node]
	
	:
		{node = self.node("direct_declarator");}
		(qualified_id LPAREN (RPAREN|declaration_specifiers) )=>	// Must be function declaration
		id = qualified_id {node.set_leaf(id);}
		{self.declaratorID(id, qiFun);}
		LPAREN {self.declaratorParameterList(0);}
		(pl = parameter_list {node.add_child(pl);} )?
		RPAREN {self.declaratorEndParameterList(0);}
		(tq = type_qualifier {node.add_child(self.node(tq));} )*
		(es = exception_specification {node.add_child(es);} )?
	|	(qualified_id LPAREN qualified_id)=>	// Must be class instantiation
		{node = self.node("direct_declarator");}
		id = qualified_id {node.set_leaf(id);}
		{self.declaratorID(id,qiVar);}
		LPAREN
		el = expression_list {node.add_child(el);}
		RPAREN
	|
		(qualified_id LSQUARE)=>	// Must be array declaration
		{node = self.node("direct_declarator");}
		id = qualified_id {node.set_leaf(id);}
		{if (self._td == true): self.declaratorID(id, qiType);}
		{if (self._td != true): self.declaratorID(id, qiVar);}
		{self.is_address = false; self.is_pointer = false;}
		(options {warnWhenFollowAmbig = false;}:
                 LSQUARE (ce = constant_expression {node.add_child(ce);})?
                 RSQUARE)+
		{self.declaratorArray();}
		
	|
		{node = self.node("direct_declarator");}
		id = qualified_id {node.set_leaf(id);}
		{if (self._td == true): self.declaratorID(id,qiType);}
		{if (self._td != true): self.declaratorID(id,qiVar);}
		{self.is_address = false; self.is_pointer = false;}
	|	
		{node = self.node("direct_declarator");}
		// DW 24/05/04 This block probably never entered as dtor selected out earlier
		//	Note In fact no dictionary entries for ctor or dtor	
		TILDE dtor:ID {self.declaratorID(dtor.getText(),qiDtor);}	// Note "class" not recorded in CPPSymbol
		{printf("%d warning direct_declarator5 entered unexpectedly with %s\n",
				LT(1).getLine(),dtor.getText());}
		LPAREN {self.declaratorParameterList(0);}
		(pl = parameter_list)?
		RPAREN {self.declaratorEndParameterList(0);}
		{node.add_child(self.node("unfinished_direct_declarator"));}
	|	
		LPAREN d = declarator {node = d;} RPAREN ds = declarator_suffixes {node.add_child(ds);}
	;

declarator_suffixes returns [node]
	{node = self.node("declarator_suffixes");}
	:
	(
		(options {warnWhenFollowAmbig = false;}:
		 LSQUARE (cx = constant_expression {node.add_child(cx);})? RSQUARE)+
		{self.declaratorArray();}
	|	{(not((self.LA(1)==LPAREN) and (self.LA(2)==ID))or(self.qualifiedItemIsOneOf(qiType|qiCtor,1)))}?
		LPAREN {self.declaratorParameterList(0);}
		(pl = parameter_list {node.add_child(pl);})?
		RPAREN {self.declaratorEndParameterList(0);}
		(tq = type_qualifier {node.add_child(self.node(tq));})*
		(es = exception_specification {node.add_child(es);})?
//	|	// DW 28/06/04 deleted Assume either following bracketed declaration
//		// empty
	)
	;

/* I think something is weird with the context-guards for predicates;
 * as a result I manually hoist the appropriate pred from ptr_to_member
 *
 * TER: warning: seems that "ID::" will always bypass and go to 2nd alt :(
 */
function_declarator [definition] returns [node]
	{node = self.node("function_declarator");}
	:	
		//{( !(self.LA(1)==SCOPE||self.LA(1)==ID) || self.qualifiedItemIsOneOf(qiPtrMember) )}?
		(ptr_operator)=> po = ptr_operator {node.set_leaf(po);}
		fd = function_declarator[definition] {node.add_child(fd);}
	|	
		fdd = function_direct_declarator[definition] {node.add_child(fdd);}
	;

function_direct_declarator [definition] returns [node]
	{node = self.node("function_direct_declarator");}
	:
		/* predicate indicate that plain ID is ok here; this counteracts any
		 * other predicate that gets hoisted (along with this one) that
		 * indicates that an ID is a type or whatever.  E.g.,
		 * another rule testing self.isTypeName() alone, implies that the
		 * the ID *MUST* be a type name.  Combining self.isTypeName() and
		 * this predicate in an OR situation like this one:
		 * ( declaration_specifiers ... | function_declarator ... )
		 * would imply that ID can be a type name OR a plain ID.
		 */
		(	// fix prompted by (isdigit)() in xlocnum
			LPAREN
			q = qualified_id {node.set_leaf(q);}
			{self.declaratorID(q,qiFun);}
			RPAREN
		|
			(a = attribute {node.add_child(a);} )*
			q = qualified_id {node.set_leaf(q);}
			{self.declaratorID(q,qiFun);}
		)
		LPAREN 
		{self.functionParameterList();}
		{if (self.K_and_R == false): self.in_parameter_list = true;}
		(pl = parameter_list {node.add_child(pl);} )? 
		{if (self.K_and_R == false): self.in_parameter_list = false;}
		{if (self.K_and_R != false): self.in_parameter_list = true;}
		RPAREN
		(an = func_asm_name {node.add_child(an);})?
		(options{warnWhenFollowAmbig = false;}:
		 tq = type_qualifier {node.add_child(self.node(tq));})*
		(ASSIGNEQUAL OCTALINT {node.add_child(self.node("purevirtual"));})?	// The value of the octal must be 0
		{self.functionEndParameterList(definition);}
		(es = exception_specification {node.add_child(es);})?
	;

/* nfd: GCC extension, allows one to set the asm name of a function (the name
 * against which the function is linked).
 * Refer http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Asm-Labels.html
*/
func_asm_name returns [node]
	:
	{node = self.node("func_asm_name");}
	("asm" | "__asm" | "__asm__")
	LPAREN
	(sl:StringLiteral {node.extend_leaf(sl.getText());})+
	RPAREN
	;

ctor_definition returns [node]
	{node = self.node("ctor_definition");}
	:
	ch = ctor_head {node.add_child(ch);}
	cb = ctor_body {node.add_child(cb);}
	{endConstructorDefinition();}
	;

ctor_head returns [node]
	{node = self.node("ctor_head");}
	:
	cds = ctor_decl_spec {node.add_child(cds);}
	cd = ctor_declarator[1] {node.add_child(cd);}
	;

ctor_decl_spec returns [node]
	{node = self.node("ctor_decl_spec");}
	:
	(("inline"|"_inline"|"__inline") {node.add_child(self.node("inline"));}
	|"explicit" {node.add_child(self.node("explicit"));})*
	;

ctor_declarator[definition] returns [node]
	{node = self.node("ctor_declarator");}
	: 
	// JEL 4/3/96 qualified_id too broad DW 10/06/03 ?
	q = qualified_ctor_id {node.set_leaf(q);}
	{self.declaratorParameterList(definition);}
	LPAREN (pl = parameter_list {node.add_child(pl);} )? RPAREN
	{self.declaratorEndParameterList(definition);}
	(es = exception_specification {node.add_child(es);})?
	;

// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_id returns [q]
	
	: 
	so = scope_override
	{qitem = so;}
	id:ID	// DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
	{qitem += id.getText();}
	{q = qitem;}
	;

ctor_body returns [node]
	{node = self.node("ctor_body");}
	:
	(ci = ctor_initializer {node.add_child(ci);} )?
	cs = compound_statement {node.add_child(cs);}
	;

ctor_initializer returns [node]
	{node = self.node("unfinished_ctor_body");}
	:
	COLON superclass_init (COMMA superclass_init)*
	;

superclass_init
	 
	: 
	q = qualified_id LPAREN (el = expression_list)? RPAREN
	;

dtor_head[definition] returns [node]
	{node = self.node("dtor_head");}
	:
	dds = dtor_decl_spec {node.add_child(dds);}
	dd = dtor_declarator[definition] {node.add_child(dd);}
	;

dtor_decl_spec returns [node]
	{node = self.node("dtor_decl_spec");}
	:
	(("inline"|"_inline"|"__inline"){node.add_child(self.node("inline"));}
	|"virtual"{node.add_child(self.node("virtual"));})*
	;

dtor_declarator[definition] returns [node]
	{node = self.node("unfinished_dtor_declaration");}
	:	
	s = scope_override
	TILDE ID
	{self.declaratorParameterList(definition);}
	LPAREN RPAREN
	{self.declaratorEndParameterList(definition);}
	(es = exception_specification)?
	;

dtor_body returns [node]
	{node = self.node("dtor_body");}
	:
	cs = compound_statement {node.add_child(cs);}
	{endDestructorDefinition();}
	;

parameter_list returns [node]
	{node = self.node("parameter_list");}
	:	pdl = parameter_declaration_list {node.add_child(pdl);} (ELLIPSIS {node.set_leaf("...");} )?
	;

parameter_declaration_list returns [node]
	
	:	{node = self.node("parameter_declaration_list");}
	(	p = parameter_declaration {node.add_child(p);}
		(// Have not been able to find way of stopping warning of non-determinism between alt 1 and exit branch of block
		 COMMA p = parameter_declaration {node.add_child(p);}
		)*
	)
	;

parameter_declaration returns [node]
	
	:	{node = self.node("parameter_declaration"); self.beginParameterDeclaration();}
		(
			{not((self.LA(1)==SCOPE) and (self.LA(2)==STAR or self.LA(2)==OPERATOR)) and ( not(self.LA(1)==SCOPE or self.LA(1)==ID) or self.qualifiedItemIsOneOf(qiType|qiCtor) )}?
			ds = declaration_specifiers	{node.add_child(ds);}// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> d = declarator {node.add_child(d);}        // if arg name given
			| 
				ad = abstract_declarator {node.add_child(ad);}    // if arg name not given  // can be empty
			)
		|
			(declarator)=> d = declarator {node.add_child(d);}			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS {node.set_leaf("ellipsis");}
		)
		(ASSIGNEQUAL 
		 re = remainder_expression {node.add_child(re);} // DW 18/4/01 assignment_expression
		)?
	;

type_name returns [node]// aka type_id
	{node = self.node("type_name");}
	:
	ds = declaration_specifiers {node.add_child(ds);}
	ad = abstract_declarator {node.add_child(ad);}
	;

/* This rule looks a bit weird because (...) can happen in two
 * places within the declaration such as "void (*)()" (ptr to
 * function returning nothing).  However, the () of a function
 * can only occur after having seen either a (abstract_declarator)
 * and not after a [..] or simple '*'.  These are the only two
 * valid () func-groups:
 *    int (*)();     // ptr to func
 *    int (*[])();   // array of ptr to func
 */
abstract_declarator returns [node]
	{node = self.node("abstract_declarator");}
	:	//{( !(self.LA(1)==SCOPE||self.LA(1)==ID) || self.qualifiedItemIsOneOf(qiPtrMember) )}?
		po = ptr_operator {node.set_leaf(po);}
		ad = abstract_declarator {node.add_child(ad);}
	|	
		LPAREN ad2 = abstract_declarator RPAREN
		{node.add_child(ad2);}
		(ads = abstract_declarator_suffix {node.add_child(ads);})+
	|	
		(LSQUARE (cx = constant_expression {node.add_child(cx);})? RSQUARE {self.declaratorArray();}
		)+
	|	
		/* empty */
	;

abstract_declarator_suffix returns [node]
	{node = self.node("abstract_declarator");}
	:	
		LSQUARE (cx = constant_expression {node.add_child(cx);} )? RSQUARE
		{self.declaratorArray();}
	|
		LPAREN
		{self.declaratorParameterList(0);}
		(pl = parameter_list {node.add_child(pl);} )?
		RPAREN
		cvs = cv_qualifier_seq {node.add_child(self.node(cvs));}
		{self.declaratorEndParameterList(0);}
		(es = exception_specification {node.add_child(es);} )?
	;

exception_specification returns [node]
	{node = self.node("unfinished_exception_specification");}
	:	"throw" 
		LPAREN 
		(	(so = scope_override ID (COMMA so = scope_override ID)? )? 
		|	ELLIPSIS
		)
		RPAREN
	;

template_head returns [node]
	{node = self.node("template_head");}
	:	
		"template"
		LESSTHAN tpl = template_parameter_list {node.add_child(tpl);} GREATERTHAN
	;

template_parameter_list returns [node]
	{node = self.node("template_parameter_list");}
	:	
		{beginTemplateParameterList();}
		tp = template_parameter {node.add_child(tp);}
		(COMMA tp = template_parameter {node.add_child(tp);} )*
		{endTemplateParameterList();}
	;

/* Rule requires >2 lookahead tokens. The ambiguity is resolved 
 * correctly, however. According to the manual "...A template argument
 * that can be interpreted either as a parameter-declaration or a
 * type-argument (because its identifier is the name of an
 * already existing class) is taken as type-argument."
 * Therefore, any "class ID" that is seen on the input, should
 * match the first alternative here (it should be a type-argument).
 */
template_parameter returns [node]
	{node = self.node("unfinished_template_parameter");}
	:
	(options{generateAmbigWarnings = false;}:
		("class"|"typename") 
		(id:ID  (ASSIGNEQUAL assigned_type_name)? )?
		{templateTypeParameter(id.getText());}
	|	
		p = parameter_declaration	// DW 30/06/03 This doesn't seem to match the current standard
	)
	;

/* This is to allow an assigned type_name in a template parameter
 *	list to be defined previously in the same parameter list,
 *	as type setting is ineffective whilst guessing
 */
assigned_type_name
	
	:
	(options{generateAmbigWarnings = false;}:
		s = qualified_type ad = abstract_declarator	
	|
		ts = simple_type_specifier ad = abstract_declarator
	)
	;

// This rule refers to an instance of a template class or function
template_id	// aka template_class_name
	
	:	ID LESSTHAN tal = template_argument_list GREATERTHAN
	;

template_argument_list returns [node]
	{node = self.node("template_argument_list");}
	:	ta = template_argument {node.add_child(ta);}
	(COMMA ta = template_argument {node.add_child(ta);} )*
	;

/* Here assignment_expression was changed to shift_expression to rule out
 *  x< 1<2 > which causes ambiguities. As a result, these can be used only
 *  by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
 *  x<(1+2)> ==> ok.
 */
template_argument returns [node]
	{node = self.node("template_argument");}
	:
		{( not(self.LA(1)==SCOPE or self.LA(1)==ID) or self.qualifiedItemIsOneOf(qiType|qiCtor) )}?
		tn = type_name {node.add_child(tn);}
	|	sx = shift_expression {node.add_child(sx);}// failed in iosfwd
//	|	assignment_expression	// Inserted as per grammar summary
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

statement_list returns [node]
	{node = self.node("statement_list");}
	:	(s = statement {node.add_child(s);}
		)+
	;

statement returns [node]
	{node = self.node("statement");}
	:
	(	(declaration)=> d = declaration {node.add_child(d);}
	|	labeled_statement {node.add_child(self.node("unfinished_labeled_statement"));}
	|	s = case_statement {node.add_child(s);}
	|	ds = default_statement {node.add_child(ds);}
	|	e = expression  {node.add_child(e);} SEMICOLON! {self.end_of_stmt();}
	|	compstat = compound_statement {node.add_child(compstat);}
	|	sstat = selection_statement {node.add_child(sstat);}
	|	iterstat = iteration_statement {node.add_child(iterstat);}
	|	jumpstat = jump_statement {node.add_child(jumpstat);}
	|	SEMICOLON! {self.end_of_stmt();}
	|	try_block {node.add_child(self.node("unfinished_try_block"));}
	|	throw_statement {node.add_child(self.node("unfinished_throw_stmt"));}
	|	asmnode = asm_block {node.add_child(asmnode);}
	)
	;

labeled_statement
	
	:	ID COLON s = statement
	;

case_statement returns [node]
	{node = self.node("case_statement");}
	:	"case"
		cx = constant_expression {node.add_child(cx);}
		COLON s = statement {node.add_child(s);}
	;

default_statement returns [node]
	{node = self.node("default_statement");}
	:	"default" COLON s = statement {node.add_child(s);}
	;

compound_statement returns [node]
	{node = self.node("compound_statement");}
	:	LCURLY 
		{self.end_of_stmt(); self.enterNewLocalScope();}
		(sl = statement_list {node.add_child(sl);})?
		RCURLY {self.exitLocalScope();}
	;

/* NOTE: cannot remove ELSE ambiguity, but it parses correctly.
 * The warning is removed with the options statement
 */
selection_statement returns [node]
	
	:	
		"if"^ {node = self.node("if");} LPAREN 
		x1 = expression {node.add_child(x1);} RPAREN
		s1 = statement {node.add_child(s1);}
		(options {warnWhenFollowAmbig = false;}:
		 "else"^ s2 = statement {elsenode =  self.node("else"); elsenode.add_child(s2); node.add_child(elsenode);})?
	|	
		"switch"^ {node = self.node("switch");} LPAREN  x3 = expression {node.add_child(x3);} RPAREN
		s3 = statement {node.add_child(s3);}
	;

iteration_statement returns [node]
	{taken_x4 = 0; taken_x5 = 0;}
	:	
		"while"	 {node = self.node("while");}
		LPAREN x1 = expression RPAREN  {node.add_child(x1);}
		s1 = statement  
		{node.add_child(s1);}
	|	
		"do" {node = self.node("do");} s2 = statement "while" {node.add_child(s2);}
		LPAREN x2 = expression RPAREN {node.add_child(x2);}
		SEMICOLON! {self.end_of_stmt();} 
	|	
		"for" {node = self.node("for");} LPAREN 
		(	(declaration)=> d1 = declaration {node.add_child(d1);}
		|	x3 = expression SEMICOLON! {self.end_of_stmt();} {node.add_child(x3);}
		|	SEMICOLON! {self.end_of_stmt(); node.add_child(self.node("blank"));}
		)
		(x4 = expression {taken_x4 = 1; node.add_child(x4);})? SEMICOLON! {self.end_of_stmt();}
		{if (taken_x4 == 0): node.add_child(self.node("blank"));}

		(x5 = expression {taken_x5 = 1; node.add_child(x5);})?
		{if (taken_x5 == 0): node.add_child(self.node("blank"));}
		RPAREN s3 = statement	  {node.add_child(s3);}
	;

jump_statement returns [node]
	
	:	
	(	"goto" gotoid:ID SEMICOLON! {self.end_of_stmt();}
		{node = self.node("jump_goto"); node.set_leaf(gotoid.getText());}
	|	"continue" SEMICOLON! {self.end_of_stmt();}
		{node = self.node("jump_statement"); node.set_leaf("continue");}
	|	"break" SEMICOLON! {self.end_of_stmt();}
		{node = self.node("jump_statement"); node.set_leaf("break");}
		// DW 16/05/03 May be problem here if return is followed by a cast expression 
	|	"return" {self.in_return = true;}
//		(	options{warnWhenFollowAmbig = false;}:
//			(LPAREN {(self.qualifiedItemIsOneOf(qiType) )}? ID RPAREN)=> 
//			LPAREN ID RPAREN (expression)?	// This is an unsatisfactory fix for problem in xstring re "return (allocator);"
//											//  and in xlocale re return (_E)(_Tolower((unsigned char)_C, &_Ctype));
//			//{printf("%d CPP_parser.g jump_statement Return fix used\n",LT(1).getLine());}
//		|	(expression  
//		/* nfd: fixme: I commented out the above weirdo thing */
//		)?	SEMICOLON!
            {node = self.node("jump_statement"); node.set_leaf("return");}
	   (x = expression {node.add_child(x);} )? SEMICOLON!
		{self.in_return = false; self.end_of_stmt();}
	)
	;

try_block
	
	:	"try" compstat = compound_statement (handler)*
	;


handler
	
	:	"catch"
		{exceptionBeginHandler();}
		{self.declaratorParameterList(1);}
		LPAREN exception_declaration RPAREN
		{self.declaratorEndParameterList(1);}
		compstat = compound_statement
		{exceptionEndHandler();}
	;

exception_declaration
	
	:	pdl = parameter_declaration_list
	;

/* This is an expression of type void according to the ARM, which
 * to me means "statement"; it removes some ambiguity to put it in
 * as a statement also.
 */
throw_statement
	
	:	"throw" (ax = assignment_expression) ? SEMICOLON! {self.end_of_stmt();}
	;

using_declaration returns [node]
	{node = self.node("unfinished_using_declaration");}
	:	"using"
		("namespace" qid = qualified_id	// Using-directive
		|qid = qualified_id				// Using-declaration
		)
		SEMICOLON! {self.end_of_stmt();}
	;

asm_block returns [node]
	{node = self.node("asm_block");}
	:   std_asm_block | gcc_asm_block
	;

std_asm_block
	:	("_asm"|"__asm") LCURLY (~RCURLY)* RCURLY 
	;

gcc_asm_block
	:   ("__asm__" | "asm") ("volatile" | "__volatile__" | "__volatile")?
            LPAREN asm_code
            ((COLON | SCOPE) (asm_reg_spec)?)*
            RPAREN
	;

asm_code
	: (StringLiteral)+
	;

asm_reg_spec
	
	:
        (LSQUARE ID RSQUARE)?
        StringLiteral
        (LPAREN ex1 = expression RPAREN)?
        (COMMA (LSQUARE ID RSQUARE)? StringLiteral
        (LPAREN ex2 = expression RPAREN)? )*
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

expression returns [node]
	
	:	x = assignment_expression {node = x;}
		(COMMA x = assignment_expression {node = self.exprnode_acc(node, x, "comma");})*
	;

/* right-to-left for assignment op */
assignment_expression returns [node]
	
	:	cx = conditional_expression {node = cx;}
		(	(ASSIGNEQUAL {leaf="assignequals";} |TIMESEQUAL {leaf="timesequals";}|DIVIDEEQUAL {leaf="dividesequals";}
			|MINUSEQUAL{leaf="minusequals";}|PLUSEQUAL {leaf="plusequals";}
			|MODEQUAL{leaf="modequals";}
			|SHIFTLEFTEQUAL{leaf="shiftleftequals";}
			|SHIFTRIGHTEQUAL{leaf="shiftrightequals";}
			|BITWISEANDEQUAL{leaf="bitwiseandequals";}
			|BITWISEXOREQUAL{leaf="bitwisexorequals";}
			|BITWISEOREQUAL{leaf="bitwiseorequals";}
			)
			rx = remainder_expression {node = self.exprnode_acc(node, rx, leaf);}
		)?
	;

remainder_expression returns [node]
	
	:
		(	(conditional_expression (COMMA|SEMICOLON|RPAREN)
			)=>
			{self.assign_stmt_RHS_found += 1;}
			x = assignment_expression {node = x;}
			{if (self.assign_stmt_RHS_found > 0): self.assign_stmt_RHS_found -= 1;}
			{if (self.assign_stmt_RHS_found <= 0): assert("Error in remainder expr");}
		|	
			x = assignment_expression {node = x;}
		)
	;

conditional_expression returns [node]
	
	:	
		lx = logical_or_expression {node = lx;}
		(QUESTIONMARK e = expression COLON cx = conditional_expression
		{node = self.node("expression"); node.add_child(lx);}
		{node.add_child(e); node.add_child(cx);}
		{node.set_leaf("c_ternary");}
		)?
	;

constant_expression returns [node]
	
	:	
		cs = conditional_expression {node = cs;}
	;

logical_or_expression returns [node]
	
	:	
		x = logical_and_expression {node = x;}
		(OR x = logical_and_expression {node = self.exprnode_acc(node, x, "logicalor");})* 
	;

logical_and_expression returns [node]
	
	:	
		x = inclusive_or_expression {node = x;}
		(AND x = inclusive_or_expression {node = self.exprnode_acc(node, x, "logicaland");})* 
	;

inclusive_or_expression returns [node]
	
	:	
		x = exclusive_or_expression {node = x;}
		(BITWISEOR x = exclusive_or_expression {node = self.exprnode_acc(node, x, "bitwiseor");})*
	;

exclusive_or_expression returns [node]
	
	:	
		x = and_expression {node = x;}
		(BITWISEXOR x = and_expression {node = self.exprnode_acc(node, x, "bitwisexor");})*
	;

and_expression returns [node]
	
	:	
	x = equality_expression {node = x;}
	(AMPERSAND x = equality_expression {node = self.exprnode_acc(node, x, "bitwiseand");})*
	;

equality_expression returns [node]
	
	:	
		x = relational_expression {node = x;}
		((NOTEQUAL {leaf = "notequals";}| EQUAL {leaf = "equals";})
		x = relational_expression {node = self.exprnode_acc(node, x, leaf);})*
	;

relational_expression returns [node]
	
	:	x = shift_expression {node = x;}
		(options {warnWhenFollowAmbig = false;}:
			(	LESSTHAN {leaf = "lessthan";}
			|	GREATERTHAN {leaf = "greaterthan";}
			|	LESSTHANOREQUALTO {leaf = "lessthanorequals";}
			|	GREATERTHANOREQUALTO {leaf = "greaterthanorequals";}
			)
		 x = shift_expression {node = self.exprnode_acc(node, x, leaf);}
		)*
	;

shift_expression returns [node]
	
	:	x = additive_expression {node = x;}
	((SHIFTLEFT {leaf = "shiftleft";}| SHIFTRIGHT {leaf = "shiftright";})
	x = additive_expression {node = self.exprnode_acc(node, x, leaf);})*
	;

/* See comment for multiplicative_expression regarding #pragma */
additive_expression returns [node]
	
	:	x = multiplicative_expression {node = x;}
		(options{warnWhenFollowAmbig = false;}:
			(PLUS {leaf = "add";}| MINUS {leaf = "subtract";})
			x = multiplicative_expression
			{node = self.exprnode_acc(node, x, leaf);}
		)*
	;

/* ANTLR has trouble dealing with the analysis of the confusing unary/binary
 * operators such as STAR, AMPERSAND, PLUS, etc...  With the #pragma (now "(options{warnWhenFollowAmbig = false;}:" etc.)
 * we simply tell ANTLR to use the "quick-to-analyze" approximate lookahead
 * as full LL(k) lookahead will not resolve the ambiguity anyway.  Might
 * as well not bother.  This has the side-benefit that ANTLR doesn't go
 * off to lunch here (take infinite time to read grammar).
 */
multiplicative_expression returns [node]
	
	:	x = pm_expression {node = x;}
		(options{warnWhenFollowAmbig = false;}:
			(STAR {leaf = "multiply";}| DIVIDE {leaf = "divide";}| MOD {leaf = "modulus";})
			x = pm_expression {node = self.exprnode_acc(node, x, leaf);}
		)*
	;

/* Pointer to member operators*/
pm_expression returns [node]
	
	:	x = cast_expression {node = x;}
	((DOTMBR {leaf = ".*";}| POINTERTOMBR {leaf = "->*";})
	x = cast_expression {node = self.exprnode_acc(node, x, leaf);})*
	;

/* The string "( ID" can be either the start of a cast or
 * the start of a unary_expression.  However, the ID must
 * be a type name for it to be a cast.  Since ANTLR can only hoist
 * semantic predicates that are visible without consuming a token,
 * the semantic predicate in rule type_name is not hoisted--hence, the
 * rule is reported to be ambiguous.  I am manually putting in the
 * correctly hoisted predicate.
 *
 * Ack! Actually "( ID" might be the start of "(T(expr))" which makes
 * the first parens just an ordinary expression grouping.  The solution
 * is to look at what follows the type, T.  Note, this could be a
 * qualified type.  Yucko.  I believe that "(T(" can only imply
 * function-style type cast in an expression (...) grouping.
 *
 * We DO NOT handle the following situation correctly at the moment:
 * Suppose you have
 *    struct rusage rusage;
 *    return (rusage.fp);
 *    return (rusage*)p;
 * Now essentially there is an ambiguity here. If rusage is followed by any
 * postix operators then it is an identifier else it is a type name. This
 * problem does not occur in C because, unless the tag struct is attached,
 * rusage is not a type name. However in C++ that restriction is removed.
 * No *real* programmer would do this, but it's in the C++ standard just for
 * fun..
 *
 * Another fun one (from an LL standpoint):
 *
 *   (A::B::T *)v;      // that's a cast of v to type A::B::T
 *   (A::B::foo);    // that's a simple member access
 *
 * The qualifiedItemIs(1) function scans ahead to what follows the
 * final "::" and returns qiType if the item is a type.  The offset of
 * '1' makes it ignore the initial LPAREN; normally, the offset is 0.
 */

cast_expression returns [node]
	
	:
	(compound_literal) => x = compound_literal {node = x;} /* nfd */
	|
		{node = self.node("expression");}
		// DW 23/06/03
		(LPAREN (type_qualifier)? type_specifier[None] (ptr_operator)* RPAREN)=>
		 {node.set_leaf("cast");}
		 LPAREN (tq = type_qualifier {node.add_child(self.node(tq));})?
		 ts = type_specifier[None] {node.add_child(ts);}
		 {indirection = self.node("indirection"); node.add_child(indirection);}
		 (po = ptr_operator {indirection.extend_leaf(po);})*
		 RPAREN cx = cast_expression {node.add_child(cx);}
	|  
		x = unary_expression {node = x;}	// handles outer (...) of "(T(expr))"
	;

unary_expression returns [node]
	
	:
		(	//{!(self.LA(1)==TILDE && self.LA(2)==ID)||self.qualifiedItemIsOneOf(qiVar|qiFun|qiDtor|qiCtor)}?
			(postfix_expression)=> x = postfix_expression {node = x;}
		|	PLUSPLUS x = unary_expression
				{node = self.node("expression"); node.set_leaf("++."); node.add_child(x);}
		|	MINUSMINUS x= unary_expression
				{node = self.node("expression"); node.set_leaf("--."); node.add_child(x);}
		|	op = unary_operator x = cast_expression
				{node = self.node("expression"); node.set_leaf(op); node.add_child(x);}
		|	"sizeof" {node = self.node("expression"); node.set_leaf("sizeof");}
			(// see comment for rule cast_expression for info on predicate
			 // JEL NOTE 3/31/96 -- This won't work -- you really need to
			 // call self.qualifiedItemIsOneOf(qiType|qiCtor,1)
			 // The context should also be ( LPAREN (SCOPE|ID) )
			 //	( LPAREN ID ) => {self.isTypeName((LT(2)->getText()).data())}?
			 {(not(((self.LA(1)==LPAREN and (self.LA(2)==ID))))or(self.isTypeName((self.LT(2).getText()))))}?
				LPAREN x = type_name RPAREN {node.add_child(x);}
			|	x = unary_expression {node.add_child(x);}
			)
		|   {node = self.node("expression");}
			(s:SCOPE {node.set_leaf(s.getText());})?
			(x = new_expression {node.add_child(x);}
			|x = delete_expression {node.add_child(x);}
			)
		)
	;

postfix_expression returns [node]
	{// Purpose?
	ds = None}
	:
	(	
		options {warnWhenFollowAmbig = false;}:
		// Function-style cast must have a leading type
		{not (self.LA(1) == LPAREN)}?
		(ts = simple_type_specifier LPAREN RPAREN LPAREN)=>	// DW 01/08/03 To cope with problem in xtree (see test10.i)
		 ts = simple_type_specifier LPAREN RPAREN LPAREN (el = expression_list)? RPAREN
		{node = self.node("unfinished_postfix-expr");}
	|
		{(self.LA(1) != LPAREN)}?
		(ts = simple_type_specifier LPAREN)=>
		 ts = simple_type_specifier LPAREN (el = expression_list)? RPAREN
		{node = self.node("unfinished_postfix-expr-2");}
	|  
		px = primary_expression {node = px;}
		{prevnode = node;}
		(options {warnWhenFollowAmbig = false;}:
        	LSQUARE x = expression RSQUARE
			{node = self.node("expression"); node.set_leaf("arrayindex"); node.add_child(prevnode); node.add_child(x); prevnode = node;}
		|	LPAREN
			{node = self.node("expression"); node.set_leaf("call"); node.add_child(prevnode);}
			(x2 = expression_list {node.add_child(x2);} )?
			{prevnode = node;}
			RPAREN
		|	DOT idxpr = id_expression
			{node = self.node("expression"); node.set_leaf("postfixdot"); node.add_child(prevnode); node.add_child(idxpr);}
			{prevnode = node;}
		|	POINTERTO idxpr2 = id_expression
			{node = self.node("expression"); node.set_leaf("postfixptr");}
			{node.add_child(prevnode); node.add_child(idxpr2); prevnode = node;}
		|	PLUSPLUS 
			{node = self.node("expression"); node.set_leaf("plusplus"); node.add_child(prevnode);}
			{prevnode = node;}
		|	MINUSMINUS 
			{node = self.node("expression"); node.set_leaf("minusminus"); node.add_child(prevnode);}
			{prevnode = node;}
		)*
	|
		("dynamic_cast"|"static_cast"|"reinterpret_cast"|"const_cast")	// Note const_cast in elsewhere
		LESSTHAN ts = type_specifier[ds] (po = ptr_operator)? GREATERTHAN
		LPAREN x = expression RPAREN
		{node = self.node("unfinished_postfix-expr-3");}
	)
	;

primary_expression returns [node]
	
	:	x = id_expression {node = x;}
	|	x = constant {node = x;}
	|	"this" {node = self.node("expression"), node.set_leaf("this");}
	|	LPAREN x = expression RPAREN {node = x;}
	;

compound_literal returns [node]
	{node = self.node("compound_literal");}
	/* nfd: ISO C99 "compound literals" feature (extension) */
	: LPAREN tn = type_name {node.add_child(tn);} RPAREN
	LCURLY i = initializer {node.add_child(i);} RCURLY
	;

id_expression returns [node]
	{node = self.node("expression");
	node.set_leaf("id_expression");}
	:
		s = scope_override {node.set_value(s);}
		(	id1:ID {node.extend_value(id1.getText());}
		|	OPERATOR o = optor {node.extend_value("operator"); node.extend_value(o);}
		/* nfd: commented this out 2007-07-06 -- it seems like we can just use unary_operator in the normal way?! */
		/*|	TILDE {node.extend_value("~");}
			(STAR {node.extend_value("*");})?
			id2:ID {node.extend_value(id2.getText());}	// DW 29/07/03 STAR included to allow for *_S = ~*_S; seen in vector */
		)
	;

unary_operator returns [op]
	:	AMPERSAND {op = "unary_ampersand";}
	|	STAR {op = "unary_pointsto";}
	|	PLUS {op = "unary_plus";}
	|	MINUS {op = "unary_minus";}
	|	TILDE {op = "unary_tilde";}
	|	NOT {op = "unary_not";}
	;

/* JEL The first ()? is used to resolve "new (expr) (type)" because both
 * (expr) and (type) look identical until you've seen the whole thing.
 *
 * new_initializer appears to be conflicting with function arguments as
 * function arguments can follow a primary_expression.  [This is a full
 * LL(k) versus LALL(k) problem.  Enhancing context by duplication of
 * some rules might handle this.]
 */
new_expression returns [node]
	
	:
	(  
		"new"
		((LPAREN expression_list RPAREN)=> 
			LPAREN el = expression_list RPAREN)?
		(new_type_id | LPAREN tn = type_name RPAREN)
		(options{warnWhenFollowAmbig = false;}:	
		(new_initializer)=> new_initializer)?
	)
	{node = self.node("unfinished_new-expr");}
	;

new_initializer
	
	:	LPAREN (el = expression_list)? RPAREN
	;

new_type_id
	
	:	ds = declaration_specifiers 
		(options {warnWhenFollowAmbig = false;}:
		 //{( !(self.LA(1)==SCOPE||self.LA(1)==ID) || self.qualifiedItemIsOneOf(qiPtrMember) )}?
			new_declarator 
		)?
	;

new_declarator
	
	:	//{( !(self.LA(1)==SCOPE||self.LA(1)==ID) || self.qualifiedItemIsOneOf(qiPtrMember) )}?  
		//ptr_to_member cv_qualifier_seq 
		po = ptr_operator
		(options {warnWhenFollowAmbig = false;}:
		new_declarator ) ?
	|	direct_new_declarator
	;

ptr_operator returns [oper]
	{oper = "UNKNOWN";}
	:	(	AMPERSAND {oper = "&";}	{self.is_address = true;}
		|	("_cdecl"|"__cdecl") {oper = "_cdecl";}
		|	("_near"|"__near") {oper = "_near";}
		|	("_far"|"__far") {oper = "_far";}
		|	"__interrupt" {oper = "__interrupt";}
		|	("pascal"|"_pascal"|"__pascal") {oper = "pascal";}
		|	("_stdcall"|"__stdcall") {oper = "_stdcall";}
		|	ptm = ptr_to_member	{oper = ptm;}// e.g. STAR 
		)	
   ;

// Match A::B::*
ptr_to_member returns [ptm]
	{s = ""}
	:
	so = scope_override {s +=  so;} STAR {s +=  "*";} {self.is_pointer = true;}
	cvs = cv_qualifier_seq {s +=  cvs;}
	{ptm = s;}
	;

// Match the A::B::C:: or nothing
scope_override returns [s]
	{sitem = ""}
	:
		//{!(self.qualifiedItemIsOneOf(qiType))}?
		(SCOPE {sitem += "::";} )?
		(	options {warnWhenFollowAmbig = false;}:
			{self.scopedItem()}?
			id:ID (LESSTHAN tal=template_argument_list GREATERTHAN)? SCOPE
			{//printf("scope_override entered\n");
			sitem += id.getText();
			sitem += "::";}
		)*
	{s = sitem;}
	;

/* The "[expression]" construct conflicts with the "new []" construct
 * (and possibly others).  We used approximate lookahead for the "new []"
 * construct so that it would not try to compute full LL(2) lookahead.
 * Here, we use #pragma approx again because anytime we see a [ followed
 * by token that can begin an expression, we always want to loop.
 * Approximate lookahead handles this correctly.  In fact, approximate
 * lookahead is the same as full lookahead when all but the last lookahead
 * depth are singleton sets; e.g., {"["} followed by FIRST(expression).
 */
direct_new_declarator
	
	:
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE x = expression RSQUARE
		)+
	;

delete_expression returns [node]
	{node = self.node("delete");}
	:	"delete" (LSQUARE RSQUARE {node.set_leaf("arrayindex");} )?
		cx = cast_expression {node.add_child(cx);}
	;

expression_list returns [node]
	{node = self.node("expression");}
	:	x = assignment_expression
		{node.add_child(x);}
		(COMMA x = assignment_expression {node = self.exprnode_acc(node, x, "comma");})*
	;

constant returns [node]
	{node = self.node("expression"); node.set_leaf("literal");
	litnode = self.node("literal"); node.add_child(litnode);}
	:
	(	oi:OCTALINT {litnode.set_leaf(oi.getText()); litnode.set_name("int");}
	|	di:DECIMALINT {litnode.set_leaf(di.getText()); litnode.set_name("int");}
	|	hi:HEXADECIMALINT {litnode.set_leaf(hi.getText()); litnode.set_name("int");}
	|	cl:CharLiteral {litnode.set_leaf(cl.getText()); litnode.set_name("char");}
	|	(sl:StringLiteral {litnode.extend_leaf(sl.getText());})+ {litnode.set_name("string");}
	|	f1:FLOATONE {litnode.set_leaf(f1.getText()); litnode.set_name("float");}
	|	f2:FLOATTWO {litnode.set_leaf(f2.getText()); litnode.set_name("float");}
	|	"true" {litnode.set_leaf("true"); litnode.set_name("bool");}
	|	"false" {litnode.set_leaf("false"); litnode.set_name("bool");}
	) 
	;

optor  returns [out]
	
	:
		"new" {out = "new";}
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE RSQUARE | )		// check syntax
	|   
		"delete" {out = "delete";}
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE RSQUARE | )		// check syntax
	|	LPAREN RPAREN {out = "()";}
	|	LSQUARE RSQUARE {out = "arrayindex";}
	|	x = optor_simple_tokclass {out = x;}	//OPTOR_SIMPLE_TOKCLASS
	;

//Zuo 5/11/2001
// This is the equivalent to "#tokclass OPTOR_SIMPLE_TOKCLASS" in cplusplus.g

optor_simple_tokclass returns [out]
	:
    (PLUS|MINUS|STAR|DIVIDE|MOD|BITWISEXOR|AMPERSAND|BITWISEOR|TILDE|NOT|
	 SHIFTLEFT|SHIFTRIGHT|
	 ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
	 SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL|
	 EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
	 PLUSPLUS|MINUSMINUS|COMMA|POINTERTO|POINTERTOMBR
	)
	{out = LT(1).getText();}
	;

// Zuo 19/11/01 from next line, the Lexer is derived from stdCParser.g



class CPPLexer extends Lexer;

options
	{
	k = 3;
	exportVocab = STDC;
	testLiterals = true;
	}

// DW 4/11/02 put in to support manual hoisting
tokens
	{
	OPERATOR = "operator";
	}

{
def setOriginalSource(src):
    originalSource = src
    lineObject.setSource(src)

def setSource(src):
    lineObject.setSource(src)
  

}

/* Operators: */

ASSIGNEQUAL     : '=' ;
COLON           : ':' ;
COMMA           : ',' ;
QUESTIONMARK    : '?' ;
SEMICOLON       : ';' ;
POINTERTO       : "->" ;

/*
// DOT & ELLIPSIS are commented out since they are generated as part of
// the Number rule below due to some bizarre lexical ambiguity shme.
// DOT  :       '.' ;
// ELLIPSIS      : "..." ;
*/

LPAREN          : '(' ;
RPAREN          : ')' ;
LSQUARE         : '[' ;
RSQUARE         : ']' ;
LCURLY          : '{' ;
RCURLY          : '}' ;

EQUAL           : "==" ;
NOTEQUAL        : "!=" ;
LESSTHANOREQUALTO     : "<=" ;
LESSTHAN              : "<" ;
GREATERTHANOREQUALTO  : ">=" ;
GREATERTHAN           : ">" ;

DIVIDE          : '/' ;
DIVIDEEQUAL     : "/=" ;
PLUS            : '+' ;
PLUSEQUAL       : "+=" ;
PLUSPLUS        : "++" ;
MINUS           : '-' ;
MINUSEQUAL      : "-=" ;
MINUSMINUS      : "--" ;
STAR            : '*' ;
TIMESEQUAL      : "*=" ;
MOD             : '%' ;
MODEQUAL        : "%=" ;
SHIFTRIGHT      : ">>" ;
SHIFTRIGHTEQUAL : ">>=" ;
SHIFTLEFT       : "<<" ;
SHIFTLEFTEQUAL  : "<<=" ;

AND            : "&&" ;
NOT            : '!' ;
OR             : "||" ;

AMPERSAND       : '&' ;
BITWISEANDEQUAL : "&=" ;
TILDE           : '~' ;
BITWISEOR       : '|' ;
BITWISEOREQUAL  : "|=" ;
BITWISEXOR      : '^' ;
BITWISEXOREQUAL : "^=" ;

//Zuo: the following tokens are come from cplusplus.g

POINTERTOMBR    : "->*" ;
DOTMBR          : ".*"  ;

SCOPE           : "::"  ;

// DW 10/10/02
// Whitespace -- ignored
Whitespace	
	:	(	(' ' |'\t' | '\f')
			// handle newlines
		|	(	"\r\n"  // MS
			|	'\r'    // Mac
			|	'\n'    // Unix 
			)	{ $nl; }
			// handle continuation lines
		|	(	"\\\r\n"  // MS
			|	"\\\r"    // Mac
			|	"\\\n"    // Unix 
			)	{ $nl; }
		)	
		{$skip}
	;

Comment  
	:	"/*"   
		(	{self.LA(2) != '/'}? '*'
		|	EndOfLine { $nl;}
		|	~('*'| '\r' | '\n')
		)*
		"*/" {$skip}
	;

CPPComment
	:	"//" (~('\n' | '\r'))* EndOfLine
 		{$skip; $nl;}                     
	;

PREPROC_DIRECTIVE
	options{paraphrase = "a line directive";}
	:	'#' LineDirective
		{$skip; $nl;} 
	;

protected
ALL_TO_NL
	: (~(' ' | '\t' | '\f')) (~('\n' | '\r'))*
	;

protected 
LineDirective
	:
		("line")?  // this would be for if the directive started "#line"
		(Space)+
		n:Decimal
		(Space)+
		(sl:ALL_TO_NL)
		{
self.line_directive_handler(sl.getText(), n.getText())  // see main()
		}
		EndOfLine
	;

protected  
Space
	:	(' ' | '\t' | '\f')
	;


Pragma
	:	('#' "pragma" (~('\r' | '\n'))* EndOfLine)
		{$skip; $nl;}
	;

Error
	:	('#' "error" (~('\r' | '\n'))* EndOfLine)
		{$skip; $nl;}
	;

/* Literals: */

/*
 * Note that we do NOT handle tri-graphs nor multi-byte sequences.
 */

/*
 * Note that we can't have empty character constants (even though we
 * can have empty strings :-).
 */
CharLiteral
	:	'\'' (Escape | ~( '\'' )) '\''
	;

/*
 * Can't have raw imbedded newlines in string constants.  Strict reading of
 * the standard gives odd dichotomy between newlines & carriage returns.
 * Go figure.
 */
StringLiteral
	:	'"'
		( Escape
		|	(	"\\\r\n"   // MS 
			|	"\\\r"     // MAC
			|	"\\\n"     // Unix
			)	{ $nl; }
		|	~('"' | '\r' | '\n' | '\\')
		)*
		'"'
	;

protected
EndOfLine
	:	(	options{generateAmbigWarnings = false;}:
			"\r\n"  // MS
		|	'\r'    // Mac
		|	'\n'    // Unix
		)
	;

/*
 * Handle the various escape sequences.
 *
 * Note carefully that these numeric escape *sequences* are *not* of the
 * same form as the C language numeric *constants*.
 *
 * There is no such thing as a binary numeric escape sequence.
 *
 * Octal escape sequences are either 1, 2, or 3 octal digits exactly.
 *
 * There is no such thing as a decimal escape sequence.
 *
 * Hexadecimal escape sequences are begun with a leading \x and continue
 * until a non-hexadecimal character is found.
 *
 * No real handling of tri-graph sequences, yet.
 */

protected
Escape  
	:	'\\'
		( options{warnWhenFollowAmbig=false;}:
		  'a'
		| 'b'
		| 'f'
		| 'n'
		| 'r'
		| 't'
		| 'v'
		| '"'
		| '\''
		| '\\'
		| '?'
		| ('0'..'3') (options{warnWhenFollowAmbig=false;}: Digit (options{warnWhenFollowAmbig=false;}: Digit)? )?
		| ('4'..'7') (options{warnWhenFollowAmbig=false;}: Digit)?
		| 'x' (options{warnWhenFollowAmbig=false;}: Digit | 'a'..'f' | 'A'..'F')+
		)
	;

/* Numeric Constants: */

protected
Digit
	:	'0'..'9'
	;

protected
Decimal
	:	('0'..'9')+
	;

protected
LongSuffix
	:	'l'
	|	'L'
	;

protected
UnsignedSuffix
	:	'u'
	|	'U'
	;

protected
FloatSuffix
	:	'f'
	|	'F'
	;

protected
Exponent
	:	('e' | 'E') ('+' | '-')? (Digit)+
	;

protected
Vocabulary
	:	'\3'..'\377'
	;

Number
	:	( (Digit)+ ('.' | 'e' | 'E') )=> (Digit)+
		( '.' (Digit)* (Exponent)? {_ttype = FLOATONE;} //Zuo 3/12/01
		| Exponent                 {_ttype = FLOATTWO;} //Zuo 3/12/01
		)                          //{_ttype = DoubleDoubleConst;}
		(FloatSuffix               //{_ttype = FloatDoubleConst;}
		|LongSuffix                //{_ttype = LongDoubleConst;}
		)?

	|	("...")=> "..."            {_ttype = ELLIPSIS;}

	|	'.'                        {_ttype = DOT;}
		(	(Digit)+ (Exponent)?   {_ttype = FLOATONE;} //Zuo 3/12/01
                                   //{_ttype = DoubleDoubleConst;}
			(FloatSuffix           //{_ttype = FloatDoubleConst;}
			|LongSuffix            //{_ttype = LongDoubleConst;}
			)?
		)?

	|	'0' ('0'..'7')*            //{_ttype = IntOctalConst;}
		(LongSuffix                //{_ttype = LongOctalConst;}
		|UnsignedSuffix            //{_ttype = UnsignedOctalConst;}
		)*                         {_ttype = OCTALINT;}

	|	'1'..'9' (Digit)*          //{_ttype = IntIntConst;}
		(LongSuffix                //{_ttype = LongIntConst;}
		|UnsignedSuffix            //{_ttype = UnsignedIntConst;}
		)*                         {_ttype = DECIMALINT;}  

	|	'0' ('x' | 'X') ('a'..'f' | 'A'..'F' | Digit)+
                                   //{_ttype = IntHexConst;}
		(LongSuffix                //{_ttype = LongHexConst;}
		|UnsignedSuffix            //{_ttype = UnsignedHexConst;}
		)*                         {_ttype = HEXADECIMALINT;}   
	;

ID
	options {testLiterals = true;}
	:	( 'a'..'z' | 'A'..'Z' | '_' )
		( 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' )*
	;

